import Blobscanner.*;
import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.*;
import processing.video.*;
import controlP5.*;

ControlP5 controlP5;
Textlabel labelBlobs;
PImage blobs;
CameraInterpreter cameraInterpreter;
FakeCamInterpreter fakeCamInterpreter;
ImageInterpreter imageInterpreter;
IInterpreter interpreter;
PVector []  edge  ; 
int i;
boolean blobsFound = false;
boolean readMap = false;

SurfaceFactory factory;

// A reference to our box2d world
PBox2D box2d;
// An ArrayList of particles that will fall on the surface
ArrayList<Particle> particles;
ArrayList<Lollipop> lollipops;
// An object to store information about the uneven surface
ArrayList<ISurface> surfaces;




void setup(){
  size(800, 600);
  smooth();
  controlP5 = new ControlP5(this);
  // Choose your Interpreter source - it could be a jpg or the camera input
  cameraInterpreter = new CameraInterpreter(this);
  fakeCamInterpreter = new FakeCamInterpreter(this);
  imageInterpreter = new ImageInterpreter(this);
  interpreter = imageInterpreter;
  interpreter.init();
  
  factory = new SurfaceFactory();
  
  // Initialize box2d physics and create the world
  box2d = new PBox2D(this);
  box2d.createWorld();
  // We are setting a custom gravity
  box2d.setGravity(0, -20);

  // Create the empty list
  particles = new ArrayList<Particle>();
  surfaces = new ArrayList<ISurface>();
  lollipops = new ArrayList<Lollipop>();
  
  
  // GUI Controls
  controlP5.addBang("bang",10,20,20,20).setTriggerEvent(Bang.RELEASE);
  controlP5.controller("bang").setLabel("read map data");
  
  // GUI Controls
  controlP5.addBang("camBlobReader",10,110,20,20).setTriggerEvent(Bang.RELEASE);
  controlP5.controller("camBlobReader").setLabel("use the current cam blob data");
  
  Radio r = controlP5.addRadio("interpreterRadio",10,60);
  r.add("Easy Map",0);
  r.add("Complex Map",1);
  r.add("Camera Map",2);

  labelBlobs = controlP5.addTextlabel("label","Blob Detection.",10,150);
}
 
void draw(){
  
  // Check if the map data is already interpreted --> This happens during pressing the key "r";
  if(readMap) {
    // if everything is analyszed, start and simulate the physics
    if(interpreter.hasFoundBlobs() && factory.hasCreated()){
      //////////////////
      // If the mouse is pressed, we make new particles
      if (mousePressed) {
        int val = round(random(0,1));
        
        if(val == 0) {
          float sz = random(2,8);
          particles.add(new Particle(mouseX,mouseY,sz));
        } else {
          Lollipop p = new Lollipop(mouseX,mouseY);
          lollipops.add(p);
        }
      }
    
      // We must always step through time!
      box2d.step();

      // Render every visual feedback
      background(200);
      // Draw all surfaces
      for (ISurface s: surfaces) {
        if(s != null)
          s.display();
      }
      
      // Draw all particles
      for (Particle p: particles) {
        if(p != null)
          p.display();
      }
      
      for (Lollipop p: lollipops) {
        p.display();
      }
    
      // Particles that leave the screen, we delete them
      // (note they have to be deleted from both the box2d world and our list
      for (int i = particles.size()-1; i >= 0; i--) {
        Particle p = particles.get(i);
        if (p != null && p.done()) {
          particles.remove(i);
        }
      }
      
      for (int i = lollipops.size()-1; i >= 0; i--) {
        Lollipop p = lollipops.get(i);
        if (p.done()) {
          lollipops.remove(i);
        }
      }
    
      // Just drawing the framerate to see how many particles it can handle
      fill(0);
      text("framerate: " + (int)frameRate,12,16);
    } else {
      // no blobs and objects are found, still looking for some
      interpreter.findBlobs();
    }
  } else {
    background(200);
  }
}

void keyPressed() {

  // REad the map data by pressing 'r'
  if(key == 'r' || keyCode == 82)
  {
    if(readMap == false) {
      readingMap();
    } else {
      readMap = false;
      // Delete the old game graphics
      for (ISurface s: surfaces) {
        if(s != null)
          s.killBody();
      }
      surfaces.clear();
    
      // Draw all particles
      for (Particle p: particles) {
        if(p != null)
          p.killBody();
      }
      particles.clear();
      
      for (Lollipop p: lollipops) {
        if(p != null)
          p.killBody();
      }
      lollipops.clear();
      
      // Create the map completely new
      interpreter.init();
      factory.init();
      readingMap();
    }
  }
}
/////////////////////////////////////////////////
// ControlP5 Gui Event handlers
public void camBlobReader() {
  // for camera input the reading process is a little bit different.
  if(interpreter instanceof CameraInterpreter) {
    CameraInterpreter t = (CameraInterpreter) interpreter;
    t.useBlobData();
  }
  
    // create the surface objects based on the image data
  if(interpreter.hasFoundBlobs() && !factory.hasCreated())
  {
    for (ISurface s: surfaces) {
        if(s != null)
          s.killBody();
      }
      surfaces.clear();
    factory.init();
    factory.create(interpreter.getBlobList(),surfaces);
  }
  
  readMap = true;
}

// Reading and creating a new map
public void bang() {
 if(readMap == false) {
    readingMap();
  } else {
    readMap = false;
    // Delete the old game graphics
    for (ISurface s: surfaces) {
      if(s != null)
        s.killBody();
    }
    surfaces.clear();
  
    // Draw all particles
    for (Particle p: particles) {
      if(p != null)
        p.killBody();
    }
    particles.clear();
    
    for (Lollipop p: lollipops) {
        if(p != null)
          p.killBody();
      }
      lollipops.clear();
    // Create the map completely new
    interpreter.init();
    factory.init();
    readingMap();
  }
}

// chaning the interpreter
void interpreterRadio(int theID) {
  switch(theID) {
    case(0): 
      interpreter = imageInterpreter;    
      break;  
    case(1):
      interpreter = fakeCamInterpreter;
      break;
    case(2):
      interpreter = cameraInterpreter;
      break;
  }
  println("radio changed");
}
///////////////////////////////////////
// Helper function
void readingMap() {
    // Find blobs
  if(!interpreter.hasFoundBlobs()) {
    interpreter.findBlobs();
  }
  
  // create the surface objects based on the image data
  if(interpreter.hasFoundBlobs() && !factory.hasCreated())
  {
    factory.create(interpreter.getBlobList(),surfaces);
  }
  
  readMap = true;
}
